package com.itheima.project.face.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.itheima.project.basic.ResponseWrap;
import com.itheima.project.constant.SuperConstant;
import com.itheima.project.constant.security.UserCacheConstant;
import com.itheima.project.constant.sms.SmsConstant;
import com.itheima.project.core.enums.security.UserEnum;
import com.itheima.project.exception.ProjectException;
import com.itheima.project.face.UserFace;
import com.itheima.project.feign.FileFeign;
import com.itheima.project.feign.SmsSendFeign;
import com.itheima.project.pojo.Role;
import com.itheima.project.pojo.User;
import com.itheima.project.service.IUserAdapterService;
import com.itheima.project.service.IUserService;
import com.itheima.project.utils.BeanConv;
import com.itheima.project.utils.EmptyUtil;
import com.itheima.project.utils.ExceptionsUtil;
import com.itheima.project.vo.file.FileVo;
import com.itheima.project.vo.security.UserVo;
import com.itheima.project.vo.sms.SendMessageVo;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RBucket;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.cache.annotation.Caching;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @ClassName UserFaceImpl.java
 * @Description 用户Face接口实现
 */
@Slf4j
@Component
public class UserFaceImpl implements UserFace {

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    @Autowired
    IUserService userService;

    @Autowired
    IUserAdapterService userAdapterService;

    @Autowired
    FileFeign fileFeign;

    @Autowired
    SmsSendFeign smsSendFeign;

    @Autowired
    RedissonClient redissonClient;

    @Override
    public Boolean sendLoginCode(String mobile) throws ProjectException {
        String key = SuperConstant.LOGIN_CODE+mobile;
        //存储手机发送的验证码到存在中
        RBucket<String> bucket = redissonClient.getBucket(key);
        String code = String.valueOf((int)((Math.random()*9+1)*100000));
        bucket.set(code,300,TimeUnit.SECONDS);
        String templateNo = "template_00001";
        String sginNo= "sign_0001";
        String loadBalancerType= SmsConstant.ROUND_ROBIN;
        Set<String> mobiles=new HashSet<>();
        mobiles.add(mobile);
        LinkedHashMap<String,String> templateParam = new LinkedHashMap<>();
        templateParam.put("code",code);
        SendMessageVo sendMessageVo = SendMessageVo.builder()
            .templateNo(templateNo)
            .sginNo(sginNo)
            .loadBalancerType(loadBalancerType)
            .mobiles(mobiles)
            .templateParam(templateParam)
            .build();
        ResponseWrap<Boolean> responseWrap = smsSendFeign.sendSmsForMq(sendMessageVo);
        return responseWrap.getDatas();
    }

    @Override
    @Cacheable(value = UserCacheConstant.PAGE,key ="#pageNum+'-'+#pageSize+'-'+#userVo.hashCode()")
    public Page<UserVo> findUserVoPage(UserVo userVo,
                                       int pageNum,
                                       int pageSize)throws ProjectException {
        try {
            Page<User> page = userService.findUserVoPage(userVo, pageNum, pageSize);
            Page<UserVo> pageVo = BeanConv.toPage(page,UserVo.class);
            //结果集转换
            List<UserVo> userVoList = pageVo.getRecords();
            if (!EmptyUtil.isNullOrEmpty(userVoList)){
                userVoList.forEach(n->{
                    //处理图片
                    ResponseWrap<List<FileVo>> responseWrap = fileFeign
                            .findFileVoByBusinessId(FileVo.builder().businessId(n.getId()).build());
                    if (!EmptyUtil.isNullOrEmpty(responseWrap.getDatas())){
                        n.setFileVo(responseWrap.getDatas().get(0));
                    }else {
                        n.setFileVo(new FileVo());
                    }
                    //处理角色
                    List<Role> roles = userAdapterService.findRoleByUserId(n.getId());
                    List<String> roleIdList = new ArrayList<>();
                    for (Role role : roles) {
                        roleIdList.add(String.valueOf(role.getId()));
                    }
                    String[] roleIds = new String[roleIdList.size()];
                    roleIdList.toArray(roleIds);
                    n.setHasRoleIds(roleIds);
                });
            }
            pageVo.setRecords(userVoList);
            return pageVo;
        } catch (Exception e) {
            log.error("查询用户列表异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(UserEnum.PAGE_FAIL);
        }
    }

    @Override
    @GlobalTransactional
    @Caching(evict = {@CacheEvict(value = UserCacheConstant.PAGE,allEntries = true),
            @CacheEvict(value = UserCacheConstant.LIST,allEntries = true),
            @CacheEvict(value = UserCacheConstant.USERNAME,key = "#result.username"),
            @CacheEvict(value = UserCacheConstant.MOBILE,key = "#result.mobile",condition = "#result.mobile!=null"),
            @CacheEvict(value = UserCacheConstant.WECHAT,key = "#result.openId",condition = "#result.openId!=null")},
            put={@CachePut(value = UserCacheConstant.BASIC,key = "#result.id")})
    public UserVo createUser(UserVo userVo)throws ProjectException {
        try {
            String plainPassword = userVo.getPassword();
            String password = bCryptPasswordEncoder.encode(plainPassword);
            userVo.setPassword(password);
            UserVo userVoResult = BeanConv.toBean(userService.createUser(userVo), UserVo.class);
            //绑定附件
            if (!EmptyUtil.isNullOrEmpty(userVoResult)&&!EmptyUtil.isNullOrEmpty(userVo.getFileVo())){
                fileFeign.bindBusinessId(FileVo.builder().businessId(userVoResult.getId()).id(userVo.getFileVo().getId()).build());
                userVoResult.setFileVo(FileVo.builder()
                    .pathUrl(userVo.getFileVo().getPathUrl())
                    .businessId(userVoResult.getId())
                    .id(userVo.getFileVo().getId()).build());
            }
            //处理角色
            userVoResult.setHasRoleIds(userVo.getHasRoleIds());
            return userVoResult;
        } catch (Exception e) {
            log.error("保存用户异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(UserEnum.CREATE_FAIL);
        }

    }

    @Override
    @GlobalTransactional
    @Caching(evict = {@CacheEvict(value = UserCacheConstant.PAGE,allEntries = true),
            @CacheEvict(value = UserCacheConstant.LIST,allEntries = true),
            @CacheEvict(value = UserCacheConstant.USERNAME,key = "#userVo.username"),
            @CacheEvict(value = UserCacheConstant.MOBILE,key = "#result.mobile",condition = "#result.mobile!=null"),
            @CacheEvict(value = UserCacheConstant.WECHAT,key = "#result.openId",condition = "#result.openId!=null"),
            @CacheEvict(value = UserCacheConstant.ROLES,key = "#userVo.id"),
            @CacheEvict(value = UserCacheConstant.RESOURCES,key = "#userVo.id"),
            @CacheEvict(value = UserCacheConstant.BASIC,key = "#userVo.id")})
    public UserVo updateUser(UserVo userVo)throws ProjectException {
        try {
            Boolean flag = userService.updateUser(userVo);
            if (flag){
                //移除业务原图片，并绑定新的图片到业务上
                fileFeign.replaceBindBusinessId(
                        FileVo.builder()
                        .businessId(userVo.getId())
                        .id(userVo.getFileVo().getId())
                        .build());
                return userVo;
            }else {
                log.error("修改用户异常！");
                throw new ProjectException(UserEnum.UPDATE_FAIL);
            }
        } catch (Exception e) {
            log.error("修改用户异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(UserEnum.UPDATE_FAIL);
        }
    }

    @Override
    @GlobalTransactional
    @Caching(evict = {@CacheEvict(value = UserCacheConstant.PAGE,allEntries = true),
            @CacheEvict(value = UserCacheConstant.LIST,allEntries = true),
            @CacheEvict(value = UserCacheConstant.USERNAME,allEntries = true),
            @CacheEvict(value = UserCacheConstant.MOBILE,allEntries = true),
            @CacheEvict(value = UserCacheConstant.WECHAT,allEntries = true),
            @CacheEvict(value = UserCacheConstant.ROLES,allEntries = true),
            @CacheEvict(value = UserCacheConstant.RESOURCES,allEntries = true)})
    public Boolean deleteUser(String[] checkedIds)throws ProjectException {
        try {
            Boolean flag = userService.deleteUser(checkedIds);
            if (flag){
                //删除图片
                for (String checkedId : checkedIds) {
                    fileFeign.deleteFileVoByBusinessId(FileVo.builder().businessId(Long.valueOf(checkedId)).build());
                }
            }
            return flag;
        } catch (Exception e) {
            log.error("删除用户异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(UserEnum.DELETE_FAIL);
        }

    }

    @Override
    @Cacheable(value = UserCacheConstant.LIST)
    public List<UserVo> findUserVoList()throws ProjectException {
        try {
            return BeanConv.toBeanList(userService.findUserVoList(),UserVo.class);
        } catch (Exception e) {
            log.error("查找用户list异常：{}", ExceptionsUtil.getStackTraceAsString(e));
            throw new ProjectException(UserEnum.SELECT_USER_LIST_FAIL);
        }
    }

}
